/*
 * Copyright (c) 2022 Chipsea Technologies (Shenzhen) Corp., Ltd.
 *
 * HDF is dual licensed: you can use it either under the terms of
 * the GPL, or the BSD license, at your option.
 * See the LICENSE file in the root of this repository for complete details.
 */

#include <securec.h>
#include "osal_file.h"
#include "hdf_log.h"
#include "ppg_cs1262.h"

#define PPG_CONFIG_START_MAGIC 0x1262
#define HDF_LOG_TAG hdf_sensor_cs1262_fw
#define REG_TAB_INDEX_HALF 2

static Cs1262RegConfigTab g_heartRegTab = {
    0x1262,
    0x0020,
    {
        0x0029, 0x473D, 0x003D, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x0000, 0x0000, 0x0000, 0x0000
    },
    {
        0x02C2, 0x0040, 0x0080, 0x0020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x0000, 0x00FF, 0xFFFF
    },
    {
        0x4224, 0x2224, 0x2222, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x0600, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x7000, 0x0050, 0x70A0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x7028, 0x0050, 0x70C8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x7028, 0x0028, 0x00A0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x7000, 0x00F0, 0x70A0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x0010, 0x0000, 0x0000, 0x0000, 0x0000
    },
    {
        0x0300, 0x0000, 0x0000, 0x0500, 0x000A, 0x0001, 0x0000, 0x0000, 0x0000, 0x1E0F, 0x0002, 0x0028,
        0x579E, 0x579E, 0x579E, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x0840, 0x0800, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x0000, 0x0000
    },
    {
        0x6160, 0x0020, 0x0202, 0x0000, 0x2200, 0x7FFF, 0x00C0, 0x01F4, 0x0000, 0x0000, 0x0000, 0x0000,
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
        0x0000
    },
    {
        0x0429, 0x0000, 0x0064, 0x000A, 0x0002, 0x0882, 0x00DF, 0x0223, 0x0002, 0x0000,
    },
    0x00F9
};

static struct PpgModeTab g_ppgModeTab[] = {
    { .mode = HEART_RATE_MODE, .regTab = &g_heartRegTab },
};

static int32_t validateTab(uint8_t *regTab, uint16_t valiSize)
{
    uint8_t checksum = 0;
    uint16_t index = 0;

    if (((uint16_t *)regTab)[0] != PPG_CONFIG_START_MAGIC) {
        HDF_LOGE("%s: validateTab invalid", __func__);
        return HDF_FAILURE;
    }

    /* real checksum stored in the last 2 bytes, needs to be removed during calculation */
    for (index = 0; index < valiSize - 2; index++) {
        checksum += regTab[index];
    }

    /* real checksum stored in the last 2 bytes, and one item of regTab has 2 bytes,
     * needs to be divided by 2 when calculating the real checksum's index.
     */
    index = (valiSize / REG_TAB_INDEX_HALF) - 1;
    return (checksum == ((uint16_t *)regTab)[index]) ? HDF_SUCCESS : HDF_FAILURE;
}

int32_t Cs1262Loadfw(enum PpgMode mode, Cs1262RegConfigTab **configTab)
{
    int32_t ret;

    for (uint8_t index = 0; index < HDF_ARRAY_SIZE(g_ppgModeTab); index++) {
        if (g_ppgModeTab[index].mode == mode) {
            ret = validateTab((uint8_t *)(g_ppgModeTab[index].regTab), sizeof(*g_ppgModeTab[index].regTab));
            if (ret != HDF_SUCCESS) {
                HDF_LOGE("%s: validateTab fail mode = %d", __func__, mode);
                return HDF_FAILURE;
            }
            *configTab = g_ppgModeTab[index].regTab;
            HDF_LOGI("%s: load success", __func__);
            return HDF_SUCCESS;
        }
    }
    HDF_LOGE("%s: Cs1262Loadfw not match, mode = %d", __func__, mode);
    return HDF_FAILURE;
}
